package com.htc;

import org.apache.lucene.queryparser.xml.builders.BooleanQueryBuilder;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;

@RestController
@SpringBootApplication
public class DemoSpringbootElasticsearchApplication {

    @Autowired
    private TransportClient client;

    /**
     * 查询
     *
     * @param id
     * @return
     */
    @GetMapping("/get/book/noval")
    @ResponseBody
    public ResponseEntity get(@RequestParam(name = "id", defaultValue = "") String id) {
        if (id.isEmpty()) {
            return new ResponseEntity(HttpStatus.NOT_FOUND);
        }
        GetResponse result = this.client.prepareGet("book", "noval", id).get();
        if (!result.isExists()) {
            return new ResponseEntity(HttpStatus.NOT_FOUND);
        }
        return new ResponseEntity(result.getSource(), HttpStatus.OK);
    }

    @PostMapping("/add/book/noval")
    @ResponseBody
    public ResponseEntity add(
            @RequestParam(name = "title") String title,
            @RequestParam(name = "author") String author,
            @RequestParam(name = "word_count") int wordCount,
            @RequestParam(name = "publish_date")
            @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
                    Date publishDate
    ) throws IOException {
        XContentBuilder contentBuilder = XContentFactory.jsonBuilder()
                .startObject()
                .field("title", title)
                .field("author", author)
                .field("word_count", wordCount)
                .field("publish_date", publishDate)
                .endObject();
        IndexResponse result = this.client.prepareIndex("book", "noval").setSource(contentBuilder).get();
        return new ResponseEntity(result.getId(), HttpStatus.OK);
    }

    @PutMapping("/update/book/noval")
    @ResponseBody
    public ResponseEntity update(
            @RequestParam(name = "title", required = false) String title,
            @RequestParam(name = "author", required = false) String author,
            @RequestParam(name = "id") String id
    ) throws IOException, ExecutionException, InterruptedException {
        UpdateRequest update = new UpdateRequest("book", "noval", id);
        XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
        if (null != title) {
            builder.field("title", title);
        }
        if (null != author) {
            builder.field("author", author);
        }
        builder.endObject();
        update.doc(builder);
        UpdateResponse result = this.client.update(update).get();
        return new ResponseEntity(result.getResult().toString(), HttpStatus.OK);
    }

    @DeleteMapping("/delete/book/noval")
    public ResponseEntity delete(@RequestParam(name = "id", defaultValue = "") String id) {
        if (id.isEmpty()) {
            return new ResponseEntity(HttpStatus.NOT_FOUND);
        }
        DeleteResponse result = this.client.prepareDelete("book", "noval", id).get();
        return new ResponseEntity(result.getResult().toString(), HttpStatus.OK);
    }

    @PostMapping("/query/book/noval")
    @ResponseBody
    public ResponseEntity query(
            @RequestParam(name = "author", required = false) String author,
            @RequestParam(name = "title", required = false) String title,
            @RequestParam(name = "gt_word_count", defaultValue = "0") int gtWordCount,
            @RequestParam(name = "gl_word_count", required = false) Integer ltWordCount
    ) {
        BoolQueryBuilder booleanQueryBuilder = QueryBuilders.boolQuery();
        if (null != author) {
            booleanQueryBuilder.must(QueryBuilders.matchQuery("author", author));
        }
        if (null != title) {
            booleanQueryBuilder.must(QueryBuilders.matchQuery("title", title));
        }
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("word_count").from(gtWordCount);
        if (ltWordCount > 0 && null != ltWordCount) {
            rangeQueryBuilder.to(ltWordCount);
        }
        booleanQueryBuilder.filter(rangeQueryBuilder);
        SearchRequestBuilder builder = this.client.prepareSearch("book")
                .setTypes("noval")
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                .setQuery(booleanQueryBuilder)
                .setFrom(0)
                .setSize(10);
        System.out.println(builder);
        SearchResponse response = builder.get();
        List<Map<String, Object>> result = new ArrayList<>();
        for (SearchHit hit : response.getHits()) {
            result.add(hit.getSource());
        }
        return new ResponseEntity(result, HttpStatus.OK);
    }


    public static void main(String[] args) {
        SpringApplication.run(DemoSpringbootElasticsearchApplication.class, args);
    }
}
